package com.biwin.module.orm.starter.service;

import com.biwin.common.api.vo.IBwVo;
import com.biwin.common.app.enums.BwOrmExceptionEnum;
import com.biwin.common.app.exception.BwNotFoundException;
import com.biwin.module.orm.api.dao.IBwHibernateDao;
import com.biwin.module.orm.api.entity.BwBasicEntity;
import com.biwin.module.orm.api.repository.IBwBasicRepository;
import com.biwin.module.orm.api.service.CurdService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * TODO
 *
 * @author biwin
 * @since 0.0.1
 */
public abstract class AbstractCurdService<T extends BwBasicEntity, V extends IBwVo, ID extends Serializable> implements CurdService<T, V, ID> {

    private final String entityName;

    private final IBwBasicRepository<T, ID> repository;

    @Autowired(required = false)
    private IBwHibernateDao<T> dao;

    public AbstractCurdService(IBwBasicRepository<T, ID> repository) {
        this.repository = repository;

        Class<T> entityClass = (Class<T>) fetchType(0);
        entityName = entityClass.getSimpleName();
    }

    /**
     * Gets actual generic type.
     *
     * @param index generic type index
     * @return real generic type will be returned
     */
    private Type fetchType(int index) {
        Assert.isTrue(index >= 0 && index <= 1, "type index must be between 0 to 1");

        return ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[index];
    }

    /**
     * 提供一个在Service 层能将实体转Vo的抽象方法
     * <p>
     * 子类需要调用定Mapper进行实现.
     *
     * @param entity
     * @return
     */
    protected abstract V toVo(T entity);

    protected T findByIdE(Long id) {
        T entity =
                repository.findById((ID) id).orElseThrow(() -> new BwNotFoundException(BwOrmExceptionEnum.ENTITY_NOT_EXIST));
        if (entity.getDeleted()) {
            throw new BwNotFoundException(BwOrmExceptionEnum.ENTITY_EXPIRED);
        }
        return entity;
    }

    @Override
    public V findByIdV(Long id) {
        T entity =
                repository.findById((ID) id).orElseThrow(() -> new BwNotFoundException(BwOrmExceptionEnum.ENTITY_NOT_EXIST));
        if (entity.getDeleted()) {
            throw new BwNotFoundException(BwOrmExceptionEnum.ENTITY_EXPIRED);
        }
        return toVo(entity);
    }

    /**
     * 根据主键逻辑删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean delete(Long id) {
        return repository.falseDelete((ID) id);
    }

}
